package cn.com.zhaoweiping.ie.convert.header;

import cn.com.zhaoweiping.ie.ExcelField;
import cn.com.zhaoweiping.ie.ExcelHelper;
import cn.com.zhaoweiping.ie.convert.HeaderConverter;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.lang.Assert;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.metadata.CellData;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import java.util.Comparator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import lombok.Data;

/**
 * 多表头转换，当一个Sheet中存在多个Table(每一个表格可能会有一个表头)<br>
 *
 * @author 冰羽
 * @version 2.2.0
 */
public class ManyHeaderConverter implements HeaderConverter {

  private LinkedHashMap<Integer, HeaderDescribe> describes;

  public ManyHeaderConverter(Map<Integer, HeaderDescribe> describes) {
    Assert.isFalse(CollectionUtil.isEmpty(describes), "多行表头描述不能为空");
    // 顺序排序
    LinkedHashMap<Integer, HeaderDescribe> linkedHashMap = Maps.newLinkedHashMap();
    Set<Integer> indexes = new TreeSet<>(Comparator.naturalOrder());
    indexes.addAll(describes.keySet());
    indexes.forEach(index -> linkedHashMap.put(index, describes.get(index)));

    this.describes = linkedHashMap;
  }

  @Override
  public Map<Integer, List<ExcelField>> convert(
      Map<Integer, CellData> headMap, AnalysisContext context) {
    Map<Integer, List<ExcelField>> excelFields = com.google.common.collect.Maps.newHashMap();

    describes.forEach(
        (index, describe) -> {
          List<CellVo> mappings = describe.getCellVos();
          Object additional = describe.getAdditional();
          final List<ExcelField> list = Lists.newArrayList();
          // 构建表头，若使用了ManyHeaderHelper默认转换则表头直接存储在额外信息字段additional中
          // 否则需要手动构建ExcelField，过程中需要不全使用过程中的ExcelField属性
          if (additional != null && additional instanceof List) {
            list.addAll((List) additional);
          } else {
            if (CollectionUtil.isNotEmpty(mappings)) {
              ManyHeaderHelper helper = ManyHeaderHelper.getInstance();
              mappings.forEach(vo -> list.add(helper.convert(vo)));
            }
          }

          // 需要存储的表头不能为空? throw new RuntimeException ?
          if (CollectionUtil.isNotEmpty(list)) {
            excelFields.put(index, list);
          }
        });

    return excelFields;
  }

  /**
   * 表头描述<br>
   *
   * @author 冰羽
   * @version 2.2.0
   */
  @Data
  public static class HeaderDescribe {

    private List<CellVo> cellVos;
    /** 额外信息 */
    private Object additional;
  }

  /**
   * 列单元格<br>
   *
   * @author 冰羽
   * @version 2.2.0
   */
  @Data
  public static class CellVo {

    /** 字段名（Java Entity） */
    private String name;
    /** 表头标题 */
    private String title;
    /** 列 */
    private Integer index;
    /** 列数据类型 */
    private Class<?> javaType;
  }

  /**
   * 多表头转换工具<br>
   *
   * @author 冰羽
   * @version 2.2.0
   */
  public abstract static class ManyHeaderHelper {
    public static ManyHeaderHelper getInstance() {
      return new ManyHeaderHelper() {
        @Override
        public HeaderDescribe buildHeaderDescribe(Class<?> clazz) {
          List<ExcelField> excelFields = new ExcelHelper().buildExcelFields(clazz);
          HeaderDescribe describe = new HeaderDescribe();
          describe.setAdditional(excelFields);

          return describe;
        }
      };
    }

    /**
     * 构建表头描述
     *
     * @param clazz 类(Entity)
     * @return
     */
    public abstract HeaderDescribe buildHeaderDescribe(Class<?> clazz);

    /**
     * ExcelField转换
     *
     * @param vo ${@link CellVo}
     * @return
     */
    public ExcelField convert(CellVo vo) {
      ExcelField excelField = new ExcelField();
      excelField.setName(vo.getName());
      excelField.setTitle(vo.getTitle());
      excelField.setCellIndex(vo.getIndex());
      excelField.setJavaType(vo.getJavaType());

      return excelField;
    }
  }
}
